package server

import (
	database2 "abdis/database"
	"abdis/interface/database"
	"abdis/lib/logger"
	"abdis/lib/sync/atomic"
	"abdis/redis/connection"
	"abdis/redis/parser"
	"abdis/redis/protocol"
	"context"
	"errors"
	"io"
	"net"
	"strings"
	"sync"
)

type Handler struct {
	activeConn sync.Map
	db         database.DB
	closing    atomic.Boolean
}

func (h *Handler) closeClient(client *connection.Connection) {
	client.Close()
	h.db.AfterClientClose(client)
	h.activeConn.Delete(client)
}

func MakeHandler() *Handler {
	return &Handler{
		db: database2.MakeStandaloneServer(),
	}
}

func (h *Handler) Handle(ctx context.Context, conn net.Conn) {
	if h.closing.Get() {
		_ = conn.Close()
		return
	}

	client := connection.MakeConnection(conn)
	h.activeConn.Store(client, struct{}{})

	ch := parser.ParseStream(conn)
	for payload := range ch {
		if payload.Err != nil {
			// 断开连接
			if errors.Is(payload.Err, io.EOF) || errors.Is(payload.Err, io.ErrUnexpectedEOF) ||
				strings.Contains(payload.Err.Error(), "use of closed network connection") {
				h.closeClient(client)
				logger.Info("connection closed: " + client.RemoteAddr())
				return
			}

			// 协议中定义的错误
			errReply := protocol.MakeErrReply(payload.Err.Error())
			_, err := client.Write(errReply.ToBytes())
			if err != nil {
				h.closeClient(client)
				logger.Info("connection closed: " + client.RemoteAddr())
				return
			}
			continue
		}

		if payload.Data == nil {
			logger.Error("empty payload")
			continue
		}

		r, ok := payload.Data.(*protocol.MultiBulkReply)
		if !ok {
			logger.Error("require multi bulk protocol")
			continue
		}

		result := h.db.Exec(client, r.Args)
		if result != nil {
			_, _ = client.Write(result.ToBytes())
		} else {
			_, _ = client.Write(protocol.UnknownErrReplyBytes)
		}

	}
}

func (h *Handler) Close() error {
	logger.Info("关闭句柄...")
	h.closing.Set(true)
	// TODO: concurrent wait
	h.activeConn.Range(func(key, value any) bool {
		client := key.(*connection.Connection)
		client.Close()
		return true
	})
	return h.db.Close()
}
